﻿using System.Reflection;
using NUnit.Core;
using SeleniumToolkit.Core;
using NUnit.Core.Extensibility;

namespace SeleniumToolkit.NUnit
{
    /// <summary>
    /// Converts the methods marked with [WebTest] within a WebTestFixture into WebTest methods
    /// </summary>
    internal class WebTestCaseBuilder : ITestCaseBuilder2
    {
        #region ITestCaseBuilder Members
        
        /// <summary>
        /// Determines if the current method should be a WebTest
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public bool CanBuildFrom(MethodInfo method)
        {
            return CanBuildFrom(method, null);
        }

        public Test BuildFrom(MethodInfo method)
        {
            return BuildFrom(method, null);
        }

        #endregion


        #region ITestCaseBuilder2 Members

        /// <summary>
        /// Construct TestCase from Method
        /// </summary>
        /// <param name="method"></param>
        /// <param name="suite"></param>
        /// <returns></returns>
        public Test BuildFrom(MethodInfo method, Test suite)
        {
            // create test case based on settings from suite
            var testCase = new WebTestCase(method);

            ApplySettingsToTest(suite, testCase);
            CheckIfTestCaseIsValid(testCase);

            NUnitFramework.ApplyCommonAttributes(method, testCase);
            NUnitFramework.ApplyExpectedExceptionAttribute(method, testCase);

            return testCase;
        }

        /// <summary>
        /// Determine if Method is a WebTest
        /// </summary>
        /// <param name="method"></param>
        /// <param name="suite"></param>
        /// <returns></returns>
        public bool CanBuildFrom(MethodInfo method, Test suite)
        {
            bool result = (!method.IsAbstract)
                          && Reflect.HasAttribute(method, "SeleniumToolkit.WebTestAttribute", true);

            return result;
        }

        #endregion

        /// <summary>
        /// Copy settings from attribute
        /// </summary>
        /// <param name="suite"></param>
        /// <param name="testCase"></param>
        /// <remarks>
        /// Settings are copied from the suite if available.
        /// </remarks>
        private static void ApplySettingsToTest(Test suite, WebTestCase testCase)
        {
            if (suite is SeleniumTestFixture)
            {
                var webFixture = (SeleniumTestFixture)suite;

                testCase.BaseUrl = webFixture.BaseUrl;
                testCase.DefaultBrowser = webFixture.DefaultBrowser;
                testCase.Timeout = webFixture.Timeout;
                testCase.SessionOwner = !webFixture.SessionOwner;
            }

            // override suite settings with attributes on method 
            SessionInfoHelper.CopyAttributes(testCase, testCase.Method);
        }

        private static void CheckIfTestCaseIsValid(WebTestCase testCase)
        {
            string reason = null;
            if (!IsValidTest(testCase, ref reason))
            {
                testCase.RunState = RunState.NotRunnable;
                testCase.IgnoreReason = reason;
            }
        }

// ReSharper disable UnusedParameter.Local
        private static bool IsValidTest(WebTestCase testCase, ref string reason)
// ReSharper restore UnusedParameter.Local
        {
            // TODO: check properties on testCase
            return true;
        }
    }
}
